/*************************************************************************
    > File Name: who.c
    > Author: Xing.Dai
    > Mail: Xing.Dai@aliyun.com 
    > Created Time: 2017-05-10 22:43
 ************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<utmp.h>
#include<fcntl.h>
#include<unistd.h>
#include<time.h>

#define SHOW_HOST		/* include remote machine on output*/
#if 0
#define ENGLISH_FORMAT
#endif

#define NRECS 3

/**
 * @Synopsis show utmp info, 
 *			 "man utmp" to look up struct utmp definition.
 *			 
 * @Param utbufp
 */
void show_info(struct utmp *utbufp)
{
	char time_str[100]; 

	if(utbufp->ut_type != USER_PROCESS){
		/* users only*/
		//printf("not process.");
		return;
	}

	printf("%-8.8s", utbufp->ut_name); // the logname
	printf(" ");	// a space
	printf("%-8.8s", utbufp->ut_line); // the tty
	printf(" ");	// a space
#ifdef ENGLISH_FORMAT
	/* Print format like: Wed June 23 */
	printf("%12.12s", ctime(&utbufp->ut_time) + 4); // Login time
#else 
	/* Print format like: xxxx-xx-xx xx:xx */
	strftime(time_str, sizeof(time_str), "%F %T", localtime(&utbufp->ut_time));
	printf("%s", time_str);
#endif
	printf(" ");	// a space
#ifdef SHOW_HOST
	if(utbufp->ut_host[0] != '\0')
		printf("(%s)", utbufp->ut_host); // the logname
#endif
	printf("\n");
}

/**
 * @Synopsis  Read next bunch of records into buffer.
 *
 * @Returns	  The account of this read buffer. 
 */
int utmp_reload(int fd, char *buf, int *cur, int *num)
{
	int read_res;
	read_res = read(fd, buf, NRECS * sizeof(struct utmp));

	*num = read_res / sizeof(struct utmp);
	*cur = 0;
	return *num;
}

/**
 * @Synopsis Read next record.
 *
 * @Returns Next utmp address.
 */
struct utmp *utmp_next(int fd, int *cur, int *num, char *buf)
{
	if(*cur == *num && utmp_reload(fd, buf, cur, num) == 0)	/* any more? */
		return NULL;

	*cur += 1;
	return (struct utmp *)(buf + (*cur - 1) * sizeof(struct utmp));
}


/**
 * @Synopsis  
 *
 * @Returns   
 */
int main()
{
	struct utmp *utbufp;	/* holds pointer to next record */
	char buf[NRECS * sizeof(struct utmp)];

	int fd = -1;		/* File descriptor. */
	int cur_rec = 0;	/* Crrent record */
	int num_recs = 0;	/* The account of Records. */

	if((fd = open(UTMP_FILE, O_RDONLY)) == -1){
		/* Open file failed.*/ 
		perror(UTMP_FILE);
		exit(-1);
	}

	while ((utbufp = utmp_next(fd, &cur_rec, &num_recs, buf)) != NULL){
		show_info(utbufp);
	}

	close(fd);

	return 0;	/* went ok*/
}

